/*
 * File:    FSBlock.cpp
 * Authors: Diane, Dan, and Tim
 * Class:   Operating Systems, Lab 2, UMD
 * Created: September 2012
 *
 * Note:  Initial code used from Chris Prince
 *        Code for DiskLinkedList, Lab 1
 *
 * Main algorithms for creating block
 */

#include "FSBlock.h"
#include "Disk.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <unistd.h> // Mac OS X
#define LINE_WIDTH 64
#define SIZEOF_INT 4

FSBlock::FSBlock(int blockNumber, int length) {
    // Pointer to an array of (usually 512 bytes of) data.
    m_blockNumber = blockNumber;
    fsblock_length = length;

    // Allocates a new RAM byte array m_buffer.
    // Length should almost always be 512 (bytes).
    m_buffer = new unsigned char[fsblock_length];

    // Initilize data to \0 so random data is not created.
    // TODO: Just call ClearBuffer()
    ClearBuffer();
//    for (int i=0; i < fsblock_length; i++) {
//        m_buffer[i] = '\0';
//        }

    // FIXME: WTF is this for?
    // Looks like numberOfBlocks comes from Disk class.
    /* if (numberOfBlocks <= 0) {
     *   printf("FSBlock.FSBlock: ERROR: Bad number of blocks: %d\n", numberOfBlocks);
     *   throw new BadNumberOfBlocksException();
     * }
     */
    }

void FSBlock::ClearBuffer() {
    for (int i=0; i < fsblock_length; i++) {
        m_buffer[i] = '\0';
        }
    }

void FSBlock::SetBuffer(unsigned char *buffer) {
    m_buffer = buffer;
}

unsigned char * FSBlock::GetBuffer() {
    return m_buffer;
}

int FSBlock::GetInt(int arrayIndex) {
    int returned_int = 0;

    char m_buffer_part[ SIZEOF_INT ];
    unsigned char* byte_position = m_buffer + (SIZEOF_INT * arrayIndex);
    memcpy(&returned_int, byte_position, SIZEOF_INT);

    return returned_int;
}

void FSBlock::SetInt(int intValue, int arrayIndex) {
    // Inspired by http://cboard.cprogramming.com/c-programming/
    // 103663-int-char-array.html
    
    unsigned char temp_char_array[SIZEOF_INT];
    // The write position is start of m_buffer + (SIZEOF_INT * 4)
    // because integers are 4 bytes long.
    unsigned char* write_position = m_buffer + (SIZEOF_INT * arrayIndex);

    bzero(temp_char_array, SIZEOF_INT);
    memcpy(temp_char_array, &intValue, SIZEOF_INT);
    memcpy(write_position, &temp_char_array, SIZEOF_INT);
}

void FSBlock::Print() {
    fflush(stdout);
    printf("\nShowing FSBlock\n");
    printf("    m_blockNumber:  %d\n", m_blockNumber);
    printf("    fsblock_length: %d\n", fsblock_length);

    printf("\n\n==Data In Hex==");
    for (int i=0; i < fsblock_length; i++) {
        if ((i%(LINE_WIDTH / 2)) == 0) {
            printf("\n");
        }
        printf("%2x ", m_buffer[i]);
    }
    printf("\n\n==Data As 8bit Digits==");
    for (int i=0; i < fsblock_length; i++) {
        if ((i%(LINE_WIDTH / 2)) == 0) {
            printf("\n");
        }
        printf("%2d ", m_buffer[i]);
    }
}

/*
*Do not need Read method.  Place holder code if we add in at end.
*Block *FSBlock::Read(int blockIndex) {
*    if (! Seek(blockIndex)) {
*        printf("FSBlock.Read: ERROR: Could not seek into block!\n");
*        return NULL;
*    }
*
*    return new Block(m_fd);
*}
*/

/*bool FSBlock::Seek(int blockIndex) {
    // Compute the offset into the file for our block index.
    int offset = Header::m_sizeOf + (blockIndex-1) * Block::m_sizeOf;

    if (lseek(m_fd, offset, SEEK_SET) == -1) {
        return false;
        }

    return true;
    }
*/

    bool FSBlock::Write(Disk *disk) {
        Disk a_disk = *disk;
        return a_disk.WriteBlock(m_blockNumber, m_buffer);
    }


FSBlock::~FSBlock() {
    // delete as [] because m_buffer was allocated as an array
    delete[] m_buffer;
}

char* FSBlock::itoa(int value, char* result, int base) {
		// check that the base if valid
		if (base < 2 || base > 36) { *result = '\0'; return result; }
	
		char* ptr = result, *ptr1 = result, tmp_char;
		int tmp_value;
	
		do {
			tmp_value = value;
			value /= base;
			*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
		} while ( value );
	
		// Apply negative sign
		if (tmp_value < 0) *ptr++ = '-';
		*ptr-- = '\0';
		while(ptr1 < ptr) {
			tmp_char = *ptr;
			*ptr--= *ptr1;
			*ptr1++ = tmp_char;
		}
		return result;
}


void FSBlock::Test(Disk *disk) {
    Disk a_disk = *disk;
    int cmd = 0;
    for (;;) {
        printf("\nmain: Enter command:\n");
        printf("   0) Exit program\n");
        printf("   1) Write FSBlock to disk\n");

        printf("Enter command: ");
        if (scanf("%d", &cmd) != 1) {
            printf("ERROR: Couldn't read from user\n"); 
	        continue;
        }

        switch (cmd) {
            case 0:
                return;

            case 1:
                Write(&a_disk);
            }
     }
}
